#include "moveReadWriteMemory.h"
#include "DB0.h"
#include "db_raw_access.h" // 假设包含 g_DBx_table 和 Area 定义等
#include "sysconf.h"
#include <string.h>

/**
 * @brief 读双字节
 *
 * @param base
 * @param max_size
 * @param byteOffset
 * @return uint16_t
 */
uint16_t process_data_Word(const uint8_t* base, size_t max_size, uint16_t byteOffset) {
  if(byteOffset * 8 + 15 >= max_size)
    return 0;
  uint16_t result = 0;
  if(byteOffset * 8 + 15 <= sizeof(g_DB0_t->I)) {
    for(int i = 0; i < 16; i++) {
      result |= ((base[i + byteOffset * 8] & 0x01) << i); // 把第 i 位放到 uint16_t 的第 i 位
    }
  } else {
    uint16_t index = GET_START_ADDR(byteOffset);
    result         = g_DB0_t->AI[index];
  }
  return result;
}
/**
 * @brief 读取字
 *
 * @param area
 * @param dbNumber
 * @param byteOffset
 * @return uint16_t
 */
uint16_t PEEK_Word(uint8_t area, uint16_t dbNumber, uint16_t byteOffset) {
  const Bool* base     = NULL;
  size_t      max_size = 0;
  DBPointer   result   = FindDBPointerByNumber(dbNumber);
  switch(area) {
    case 0x81:
      base     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I) + sizeof(g_DB0_t->AI) * 8;
      return process_data_Word(base, max_size, byteOffset);
    case 0x82:
      base     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      return process_data_Word(base, max_size, byteOffset);
    case 0x83:
      base     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      return process_data_Word(base, max_size, byteOffset);

    case 0x84:
      if(result.pointer == NULL)
        return 0;
      base     = result.pointer;
      max_size = result.size;
      if(byteOffset + 1 >= max_size)
        return 0;
      return base[byteOffset] | (base[byteOffset + 1] << 8);

    default:
      return 0;
  }
}

uint8_t process_data_Byte(const uint8_t* base, size_t max_size, uint16_t byteOffset) {
  if(byteOffset * 8 + 7 >= max_size)
    return 0;
  uint8_t result = 0;

  if(byteOffset * 8 + 7 <= sizeof(g_DB0_t->I)) {
    for(int i = 0; i < 8; i++) {
      result |= ((base[i + byteOffset * 8] & 0x01) << i); // 把第 i 位放到 uint16_t 的第 i 位
    }
  } else {
    result = *((uint8_t*) g_DB0_t->AI + byteOffset - DIQM_NUM_LEN);
  }
  return result;
}

uint8_t PEEK_Byte(uint8_t area, uint16_t dbNumber, uint16_t byteOffset) {
  const uint8_t* base     = NULL;
  size_t         max_size = 0;
  DBPointer      result   = FindDBPointerByNumber(dbNumber);

  switch(area) {
    case 0x81:
      base     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I) + sizeof(g_DB0_t->AI) * 8;
      return process_data_Byte(base, max_size, byteOffset);
    case 0x82:
      base     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      return process_data_Byte(base, max_size, byteOffset);
    case 0x83:
      base     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      return process_data_Byte(base, max_size, byteOffset);
    case 0x84:
      if(result.pointer == NULL)
        return 0;
      base     = result.pointer;
      max_size = result.size;
      if(byteOffset >= max_size)
        return 0;
      return base[byteOffset];
    default:
      return 0;
  }
}
uint32_t process_data_DWord(const uint8_t* base, size_t max_size, uint16_t byteOffset) {
  if(byteOffset * 8 + 31 >= max_size)
    return 0;
  uint32_t result = 0;

  if(byteOffset * 8 + 31 <= sizeof(g_DB0_t->I)) {
    for(int i = 0; i < 32; i++) {
      result |= ((base[i + byteOffset * 8] & 0x01) << i);
    }
  } else {
    uint16_t index = GET_START_ADDR(byteOffset);
    uint8_t* ptr   = (uint8_t*) g_DB0_t->AI + index;
    result = ((uint32_t) ptr[0]) | ((uint32_t) ptr[1] << 8) | ((uint32_t) ptr[2] << 16) | ((uint32_t) ptr[3] << 24);
  }

  return result;
}

DWord PEEK_DWord(uint8_t area, uint16_t dbNumber, uint16_t byteOffset) {
  const uint8_t* base     = NULL;
  size_t         max_size = 0;
  DBPointer      result   = FindDBPointerByNumber(dbNumber);

  switch(area) {
    case 0x81:
      base     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I) + sizeof(g_DB0_t->AI) * 8;
      return process_data_DWord(base, max_size, byteOffset);

    case 0x82:
      base     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      return process_data_DWord(base, max_size, byteOffset);
    case 0x83:
      base     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      return process_data_DWord(base, max_size, byteOffset);
    case 0x84:
      if(result.pointer == NULL)
        return 0;
      base     = result.pointer;
      max_size = result.size;

      if(byteOffset + 3 >= max_size)
        return 0;

      return (uint32_t) base[byteOffset] | ((uint32_t) base[byteOffset + 1] << 8) |
             ((uint32_t) base[byteOffset + 2] << 16) | ((uint32_t) base[byteOffset + 3] << 24);
    default:
      return 0;
  }
}

uint8_t process_data_Bool(const uint8_t* base, size_t max_size, uint16_t byteOffset, uint8_t bitOffset) {
  if(byteOffset * 8 + bitOffset >= max_size || bitOffset > 7)
    return 0;
  uint8_t result = base[byteOffset * 8 + bitOffset];
  return result;
}

uint8_t PEEK_BOOL(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, uint8_t bitOffset) {
  const uint8_t* base     = NULL;
  size_t         max_size = 0;
  DBPointer      result   = FindDBPointerByNumber(dbNumber);

  // 获取目标区域的基地址
  switch(area) {
    case 0x81:
      base     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      return process_data_Bool(base, max_size, byteOffset, bitOffset);
    case 0x82:
      base     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      return process_data_Bool(base, max_size, byteOffset, bitOffset);
    case 0x83:
      base     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      return process_data_Bool(base, max_size, byteOffset, bitOffset);

    case 0x84:
      if(result.pointer == NULL)
        return 0;
      base     = result.pointer;
      max_size = result.size;
      // 越界保护：1字节8位，所以最大 bitOffset 为 7
      if(byteOffset >= max_size || bitOffset > 7)
        return 0;
      return (base[byteOffset] >> bitOffset) & 0x01;
    default:
      return 0;
  }
}

void POKE_BOOL(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, uint8_t bitOffset, uint8_t value) {
  uint8_t*  base     = NULL;
  size_t    max_size = 0;
  DBPointer result   = FindDBPointerByNumber(dbNumber);

  switch(area) {
    case AREA_I:
      base     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      if(byteOffset * 8 + bitOffset >= max_size || bitOffset > 7)
        return;
      base[byteOffset * 8 + bitOffset] = value;
      return;
    case AREA_Q:
      base     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      if(byteOffset * 8 + bitOffset >= max_size || bitOffset > 7)
        return;
      base[byteOffset * 8 + bitOffset] = value;
      if(byteOffset == 4 && bitOffset == 6 && value == 0) {
        base[byteOffset * 8 + bitOffset] = value;
      }
      return;
    case AREA_M:
      base     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      if(byteOffset * 8 + bitOffset >= max_size || bitOffset > 7)
        return;
      base[byteOffset * 8 + bitOffset] = value;
      return;

    case AREA_DB:
      if(result.pointer == NULL)
        return;
      base     = result.pointer;
      max_size = result.size;
      if(byteOffset >= max_size || bitOffset > 7)
        return;
      if(value)
        base[byteOffset] |= (1 << bitOffset);
      else
        base[byteOffset] &= ~(1 << bitOffset);
      return;
    default:
      return;
  }
}

void POKE_Byte(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, uint8_t value) {
  uint8_t*  base     = NULL;
  size_t    max_size = 0;
  DBPointer result   = FindDBPointerByNumber(dbNumber);
  switch(area) {
    case AREA_I:
      base     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      if(byteOffset * 8 >= max_size)
        return;
      for(int i = 0; i < 8; i++) {
        base[byteOffset * 8 + i] = (value >> i) & 0x01; // 只保留最低位，结果为 0x00 或 0x01
      }
      return;
    case AREA_Q:
      base     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      if(byteOffset * 8 >= max_size)
        return;
      for(int i = 0; i < 8; i++) {
        base[byteOffset * 8 + i] = (value >> i) & 0x01; // 只保留最低位，结果为 0x00 或 0x01
      }
      return;
    case AREA_M:
      base     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      if(byteOffset * 8 >= max_size)
        return;
      for(int i = 0; i < 8; i++) {
        base[byteOffset * 8 + i] = (value >> i) & 0x01; // 只保留最低位，结果为 0x00 或 0x01
      }
      return;
    case AREA_DB:
      if(result.pointer == NULL)
        return;
      base     = result.pointer;
      max_size = result.size;
      if(byteOffset >= max_size)
        return;
      base[byteOffset] = value;
      return;
    default:
      return;
  }
}

void POKE_Word(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, uint16_t value) {
  uint8_t*  base     = NULL;
  size_t    max_size = 0;
  DBPointer result   = FindDBPointerByNumber(dbNumber);
  switch(area) {
    case AREA_I:
      base     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      if(byteOffset * 8 >= max_size)
        return;
      for(int i = 0; i < 16; i++) {
        base[byteOffset * 8 + i] = (value >> i) & 0x01; // 只保留最低位，结果为 0x00 或 0x01
      }
      return;
    case AREA_Q:
      base     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      if(byteOffset * 8 >= max_size)
        return;
      for(int i = 0; i < 16; i++) {
        base[byteOffset * 8 + i] = (value >> i) & 0x01; // 只保留最低位，结果为 0x00 或 0x01
      }
      return;
    case AREA_M:
      base     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      if(byteOffset * 8 >= max_size)
        return;
      for(int i = 0; i < 16; i++) {
        base[byteOffset * 8 + i] = (value >> i) & 0x01; // 只保留最低位，结果为 0x00 或 0x01
      }
      return;
    case AREA_DB:
      if(result.pointer == NULL)
        return;
      base     = result.pointer;
      max_size = result.size;
      if(byteOffset + 1 >= max_size)
        return;
      base[byteOffset]     = value & 0xFF;
      base[byteOffset + 1] = (value >> 8) & 0xFF;
      return;
    default:
      return;
  }
}

void POKE_BLK(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, const uint8_t* src, size_t length) {
  uint8_t*  dest     = NULL;
  size_t    max_size = 0;
  DBPointer result   = FindDBPointerByNumber(dbNumber);

  switch(area) {
    case AREA_I:
      dest     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      if((byteOffset * 8 + length * 8) >= max_size)
        return;
      for(int byte_i = 0; byte_i < length; byte_i++) {
        for(int bit_i = 0; bit_i < 8; bit_i++) {
          int dst_index   = byteOffset * 8 + byte_i * 8 + bit_i;
          dest[dst_index] = (src[byte_i] >> bit_i) & 0x01; // 提取第 bit_i 位
        }
      }
      return;
    case AREA_Q:
      dest     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      if((byteOffset * 8 + length * 8) >= max_size)
        return;
      for(int byte_i = 0; byte_i < length; byte_i++) {
        for(int bit_i = 0; bit_i < 8; bit_i++) {
          int dst_index   = byteOffset * 8 + byte_i * 8 + bit_i;
          dest[dst_index] = (src[byte_i] >> bit_i) & 0x01; // 提取第 bit_i 位
        }
      }
      return;
    case AREA_M:
      dest     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);

      if((byteOffset * 8 + length * 8) >= max_size)
        return;
      for(int byte_i = 0; byte_i < length; byte_i++) {
        for(int bit_i = 0; bit_i < 8; bit_i++) {
          int dst_index   = byteOffset * 8 + byte_i * 8 + bit_i;
          dest[dst_index] = (src[byte_i] >> bit_i) & 0x01; // 提取第 bit_i 位
        }
      }
      return;
    case AREA_DB:
      if(result.pointer == NULL)
        return;
      dest     = result.pointer;
      max_size = result.size;
      if(byteOffset + length > max_size)
        return;
      memcpy(dest + byteOffset, src, length);
      return;
    default:
      return;
  }
}

/// 这个需要时进行调整，暂不调整
void READ_LITTLE(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, uint8_t* dst, size_t length) {
  const uint8_t* src      = NULL;
  size_t         max_size = 0;
  DBPointer      result   = FindDBPointerByNumber(dbNumber);
  switch(area) {
    case AREA_I:
      src      = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      break;
    case AREA_Q:
      src      = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      break;
    case AREA_M:
      src      = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      break;
    case AREA_DB:
      if(result.pointer == NULL)
        return;
      src      = result.pointer;
      max_size = result.size;
      break;
    default:
      return;
  }

  if(byteOffset + length > max_size)
    return;
  memcpy(dst, src + byteOffset, length); // 小端字节序 = 顺序拷贝
}
/// 这个需要时进行调整，暂不调整
void WRITE_LITTLE(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, const uint8_t* src, size_t length) {
  POKE_BLK(area, dbNumber, byteOffset, src, length);
}

/// 这个需要时进行调整，暂不调整
void READ_BIG(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, uint8_t* dst, size_t length) {
  const uint8_t* src      = NULL;
  size_t         max_size = 0;
  DBPointer      result   = FindDBPointerByNumber(dbNumber);
  switch(area) {
    case AREA_I:
      src      = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      break;
    case AREA_Q:
      src      = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      break;
    case AREA_M:
      src      = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      break;
    case AREA_DB:
      if(result.pointer == NULL)
        return;
      src      = result.pointer;
      max_size = result.size;
      break;
    default:
      return;
  }

  if(byteOffset + length > max_size)
    return;

  for(size_t i = 0; i < length; ++i)
    dst[i] = src[byteOffset + length - 1 - i]; // 反向读取
}

/// 这个需要时进行调整，暂不调整
void WRITE_BIG(uint8_t area, uint16_t dbNumber, uint16_t byteOffset, const uint8_t* src, size_t length) {
  uint8_t* dest     = NULL;
  size_t   max_size = 0;

  DBPointer result = FindDBPointerByNumber(dbNumber);
  switch(area) {
    case AREA_I:
      dest     = (uint8_t*) g_DB0_t->I;
      max_size = sizeof(g_DB0_t->I);
      break;
    case AREA_Q:
      dest     = (uint8_t*) g_DB0_t->Q_W;
      max_size = sizeof(g_DB0_t->Q_W);
      break;
    case AREA_M:
      dest     = (uint8_t*) g_DB0_t->M;
      max_size = sizeof(g_DB0_t->M);
      break;
    case AREA_DB:
      if(result.pointer == NULL)
        return;
      dest     = result.pointer;
      max_size = result.size;
      break;
    default:
      return;
  }

  if(byteOffset + length > max_size)
    return;

  for(size_t i = 0; i < length; ++i)
    dest[byteOffset + i] = src[length - 1 - i]; // 反向写入
}
